package com.hzit.manager.service.impl;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSON;
import com.ruoyi.system.api.domain.Brand;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.common.aliasing.qual.Unique;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import com.hzit.manager.mapper.BrandMapper;
import com.hzit.manager.service.IBrandService;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.rowset.BaseRowSet;

/**
 * 品牌管理Service业务层处理
 * 
 * @author wf
 * @date 2024-01-15
 */
@Service
public class BrandServiceImpl implements IBrandService 
{
    @Autowired
    private BrandMapper brandMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 查询品牌管理
     * 
     * @param id 品牌管理主键
     * @return 品牌管理
     */
    @Override
    public Brand selectBrandById(Long id)
    {
        return brandMapper.selectBrandById(id);
    }

    /**
     * 查询品牌管理列表
     * 
     * @param brand 品牌管理
     * @return 品牌管理
     */
    @Override
    public List<Brand> selectBrandList(Brand brand)
    {
        return brandMapper.selectBrandList(brand);
    }

    /**
     * 新增品牌管理
     * 
     * @param brand 品牌管理
     * @return 结果
     */
    @Override
    public int insertBrand(Brand brand)
    {
        return brandMapper.insertBrand(brand);
    }

    /**
     * 修改品牌管理
     * 
     * @param brand 品牌管理
     * @return 结果
     */
    @Override
    public int updateBrand(Brand brand)
    {
        return brandMapper.updateBrand(brand);
    }

    /**
     * 批量删除品牌管理
     * 
     * @param ids 需要删除的品牌管理主键
     * @return 结果
     */
    @Override
    public int deleteBrandByIds(Long[] ids)
    {
        return brandMapper.deleteBrandByIds(ids);
    }

    /**
     * 删除品牌管理信息
     * 
     * @param id 品牌管理主键
     * @return 结果
     */
    @Override
    public int deleteBrandById(Long id)
    {
        return brandMapper.deleteBrandById(id);
    }

	@Override
    @Transactional          // 开启本地事务
	public void saveBrand() {
		Brand brand = new Brand();
        brand.setFirstChar("Q");
        brand.setName("七匹狼");
        // int i = 10 / 0;
        this.insertBrand(brand);
	}

	//2. 实现分布式锁方法一：Lua脚本 + Redis
    //缺点：不能完成自动续期
	@Override
	public List<Brand> findAll2() throws InterruptedException {
        List<Brand> brands = null;
        //2.1 生成一个uuid的字符串
        String uuid = UUID.randomUUID().toString().replace("-","");
        //2.2 使用setnx(相当于：setIfAbsent)命令进行加锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 200, TimeUnit.SECONDS);
        //2.3 根据是否为true,判断是否加锁成功
        if(lock){
            //2.3.1 从redsi中查询出品牌列表数据
            try{
                String hzit_brands = redisTemplate.opsForValue().get("hzit_brands");
                if(StringUtils.isNotBlank(hzit_brands)){
                    return JSON.parseArray(hzit_brands,Brand.class);
                }else {
                    System.out.println("正在从数据库中取出数据。。。");
                    //2.3.2 从数据库中取出数据
                    brands = this.selectBrandList(null);
                    //2.3.3 将数据保存到redis中
                    redisTemplate.opsForValue().set("hzit_brands",JSON.toJSONString(brands));
                }
            }finally {
                // 定义脚本片段
                String scriptStr = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                // 包装脚本对象
                RedisScript<Long> script = new DefaultRedisScript<>(scriptStr,Long.class);
                // 执行脚本
                redisTemplate.execute(script, Arrays.asList("lock"),uuid);
            }

        }else{
            Thread.sleep(100);
            this.findAll2();  // 进行自旋操作
        }

        return null;
	}

    //3. 实现分布式锁方法二：Redisson框架
    @Override
    public List<Brand> findAll3() {
        List<Brand> brands = null;
        //3.1 加锁
        RLock lock = redissonClient.getLock("redisson-lock");
        lock.lock(100,TimeUnit.SECONDS);        // 如果想使用看门狗机制，此处使用不带参数的lock方法
        // lock.lock();
        try{
            //3.1 首先，从redis中取得数据
            String mybrands = redisTemplate.opsForValue().get("mybrands");
            if(StringUtils.isNotBlank(mybrands)){
                brands = JSON.parseArray(mybrands, Brand.class);
            }else{
                System.out.println("从数据库查询数据，(redisson框架实现分布式锁！)");
                brands = this.selectBrandList(null);
                redisTemplate.opsForValue().set("mybrands", JSON.toJSONString(brands));
            }
        }finally {
            lock.unlock();
        }
        return brands;
    }
}
